#!/usr/bin/env python
#
#   Author: Tushar Jog
#   FileName: genRecords.py
#
import string
import re

vectorTemplate = "List"
hashTemplate   = "KeyValuePair"

def toHungarian(name):
    hungarian = name
    return hungarian

cppDefinitionTemplate = string.Template('''
    class $CLASSNAME : public Record {
        public:
            $CLASSNAME();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return $RECORD; }

            friend class Stream;
            friend class StdfFile;

        protected:
$MEMBERS
        };
''');
cppImplementationTemplate = string.Template('''
    /////////////////////////////////////////////////////////////////////////////
    $CLASSNAME::$CLASSNAME() {
        recordHeader = $RECORD;
$INITIALIZE
    }

    U2 $CLASSNAME::getLength(void) {
        U2 len = 0;
$LENGTH
        return len;
    }

    void $CLASSNAME::getFields( vector< pair<string,string> >& fields) {
$GETFIELD
    }

''');
csDefinitionTemplate = string.Template('''
''');
csImplementationTemplate = string.Template('''

    public class $CLASSNAME : Record {
        public $CLASSNAME() {
            recordHeader = new RecordHeader(RecordType.$RECORD);
            $INITIALIZE
        }
        public override U2 getLength() {
            U2 len = 0;
            $LENGTH
            return len;
        }
        public override void getFields( ref List< Pair<string, string> > fields) {
            $GETFIELD
        }
        public override RecordType getRecordType() { return RecordType.$RECORD; }
	public override string ToString() {
        string text = "";

        return text;
	}

        protected:
            $MEMBERS
        };

''');

#
#   Base types
#
#   key   => name of type
#   value => dictionary of [size in bytes, unsigned or not, invalid value]
base = {}
base['U1'] = { 'size': 1, 'unsigned':True,  'invalid':"0",          'default':"0"}
base['U2'] = { 'size': 2, 'unsigned':True,  'invalid':"65535",      'default':"0"}
base['U4'] = { 'size': 4, 'unsigned':True,  'invalid':"4294967295", 'default':"0"}
base['I1'] = { 'size': 1, 'unsigned':False, 'invalid':"0",          'default':"0"}
base['I2'] = { 'size': 2, 'unsigned':False, 'invalid':"-32768",     'default':"0"}
base['I4'] = { 'size': 4, 'unsigned':False, 'invalid':"0",          'default':"0"}
base['C1'] = { 'size': 1, 'unsigned':False, 'invalid':"' '",        'default':"' '"}
base['CN'] = { 'size': 0, 'unsigned':False, 'invalid':'""',         'default':''}
base['R4'] = { 'size': 4, 'unsigned':False, 'invalid':"0",          'default':"0"}
base['B1'] = { 'size': 1, 'unsigned':True,  'invalid':"0",          'default':"0"}
base['BN'] = { 'size': 0, 'unsigned':True,  'invalid':'""',         'default':'""'}
base['N1'] = { 'size': 1, 'unsigned':True,  'invalid':"0",          'default':"0"}
base['DN'] = { 'size': 0, 'unsigned':True,  'invalid':'0',         'default':'0'}
base['VN'] = { 'size': 0, 'unsigned':True,  'invalid':'0',         'default':'0'}

# Complex types
base['xU1'] = { 'size': 1, 'unsigned':True,  'invalid':"256",    'default':"0"}
base['xU2'] = { 'size': 2, 'unsigned':True,  'invalid':"65535",  'default':"0"}
base['xCN'] = { 'size': 0, 'unsigned':False, 'invalid':'""',     'default':'""'}
base['xN1'] = { 'size': 1, 'unsigned':True,  'invalid':"0",    'default':"0"}
base['xR4'] = { 'size': 4, 'unsigned':False, 'invalid':"0",          'default':"0"}

#
# STDF Record Types
#
# key   => record name
# value => list of [type, varName]
#
recordInfo = { }
recordInfo['FAR'] = [
                        ["U1", "cpuType"],
                        ["U1", "stdfVersion"]
                    ]
recordInfo['ATR'] = [
                        ["U4", "modificationTime"],
                        ["CN", "commandLine"]
                    ]
recordInfo['MIR'] = [
                        ["U4", "setupTime"],
                        ["U4", "startTime"],
                        ["U1", "stationNumber"],
                        ["C1", "modeCode"],
                        ["C1", "retestCode"],
                        ["C1", "protectionCode"],
                        ["U2", "burninTime"],
                        ["C1", "commandModeCode"],
                        ["CN", "lotID"],
                        ["CN", "partType"],
                        ["CN", "nodeName"],
                        ["CN", "testerType"],
                        ["CN", "jobName"],
                        ["CN", "jobRevision"],
                        ["CN", "sublotID"],
                        ["CN", "operatorName"],
                        ["CN", "executiveType"],
                        ["CN", "executiveVersion"],
                        ["CN", "testCode"],
                        ["CN", "testTemp"],
                        ["CN", "userText"],
                        ["CN", "auxFile"],
                        ["CN", "packageType"],
                        ["CN", "familyID"],
                        ["CN", "dateCode"],
                        ["CN", "facilityID"],
                        ["CN", "floorID"],
                        ["CN", "processID"],
                        ["CN", "operatorFrequency"],
                        ["CN", "specName"],
                        ["CN", "specVersion"],
                        ["CN", "flowID"],
                        ["CN", "setupID"],
                        ["CN", "designRevision"],
                        ["CN", "engineeringLotID"],
                        ["CN", "romCode"],
                        ["CN", "serialNumber"],
                        ["CN", "supervisorName"]
                    ]
recordInfo['MRR'] = [
                        ["U4", "finishTime"],
                        ["C1", "dispositionCode"],
                        ["CN", "userLotDescription"],
                        ["CN", "executiveLotDescription"]
                    ]
recordInfo['PCR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"],
                        ["U4", "partCount"],
                        ["U4", "retestCount", "4294967295U"],
                        ["U4", "abortCount", "4294967295U"],
                        ["U4", "goodCount", "4294967295U"],
                        ["U4", "funcCount", "4294967295U"]
                    ]
recordInfo['HBR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"],
                        ["U2", "hbinNumber"],
                        ["U4", "hbinCount"],
                        ["C1", "hbinPF"],
                        ["CN", "hbinName"]
                    ]
recordInfo['SBR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"],
                        ["U2", "sbinNumber"],
                        ["U4", "sbinCount"],
                        ["C1", "sbinPF"],
                        ["CN", "sbinName"]
                    ]
recordInfo['PMR'] = [
                        ["U2", "pmrIndex"],
                        ["U2", "channelType"],
                        ["CN", "channelName"],
                        ["CN", "physicalName"],
                        ["CN", "logicalName"],
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"]
                    ]
recordInfo['PGR'] = [
                        ["U2",   "groupIndex"],
                        ["CN",   "groupName"],
                        ["U2",   "indexCount"],
                        ["kxU2", "pmrIndex"]
                    ]
recordInfo['PLR'] = [
                        ["U2",   "groupCount"],
                        ["kxU2", "groupIndex"],
                        ["kxU2", "groupMode"],
                        ["kxU1", "groupRadix"],
                        ["kxCN", "programCharRight"],
                        ["kxCN", "returnCharRight"],
                        ["kxCN", "programCharLeft"],
                        ["kxCN", "returnCharLeft"]
                    ]

recordInfo['RDR'] = [
                        ["U2",   "numBins"],
                        ["kxU2", "retestbinNumbers"]
                    ]
recordInfo['SDR'] = [
                        ["U1",   "headNumber"],
                        ["U1",   "siteGroup"],
                        ["U1",   "siteCount"],
                        ["kxU1", "siteNumbers"],
                        ["CN",   "handlerType"],
                        ["CN",   "handlerID"],
                        ["CN",   "probeCardType"],
                        ["CN",   "probeCardID"],
                        ["CN",   "loadBoardType"],
                        ["CN",   "loadBoardID"],
                        ["CN",   "dibType"],
                        ["CN",   "dibID"],
                        ["CN",   "cableType"],
                        ["CN",   "cableID"],
                        ["CN",   "contactorType"],
                        ["CN",   "contactorID"],
                        ["CN",   "laserType"],
                        ["CN",   "laserID"],
                        ["CN",   "extraType"],
                        ["CN",   "extraID"]
                    ]
recordInfo['WIR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteGroup"],
                        ["U4", "startTime"],
                        ["CN", "waferID"]
                    ]
recordInfo['WRR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteGroup"],
                        ["U4", "finishTime"],
                        ["U4", "partCount"],
                        ["U4", "retestCount"],
                        ["U4", "abortCount"],
                        ["U4", "goodCount"],
                        ["U4", "funcCount"],
                        ["CN", "waferID"],
                        ["CN", "fabWaferID"],
                        ["CN", "waferFrameID"],
                        ["CN", "waferMaskID"],
                        ["CN", "userDescription"],
                        ["CN", "execDescription"]
                    ]
recordInfo['WCR'] = [
                        ["R4", "waferSize"],
                        ["R4", "dieHeight"],
                        ["R4", "dieWidth"],
                        ["U1", "waferUnits"],
                        ["C1", "waferFlat"],
                        ["I2", "centerX"],
                        ["I2", "centerY"],
                        ["C1", "positiveX"],
                        ["C1", "positiveY"]
                    ]
recordInfo['PIR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"]
                    ]
recordInfo['PRR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"],
                        ["B1", "partFlag"],
                        ["U2", "numTests"],
                        ["U2", "hardBin"],
                        ["U2", "softBin"],
                        ["I2", "xCoord"],
                        ["I2", "yCoord"],
                        ["U4", "testTime"],
                        ["CN", "partID"],
                        ["CN", "partText"],
                        ["BN", "partFix"]
                    ]
recordInfo['TSR'] = [
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"],
                        ["C1", "testType"],
                        ["U4", "testNumber"],
                        ["U4", "execCount"],
                        ["U4", "failCount"],
                        ["U4", "alarmCount"],
                        ["CN", "testName"],
                        ["CN", "sequencerName"],
                        ["CN", "testLabel"],
                        ["B1", "optFlag"],
                        ["R4", "testTime"],
                        ["R4", "testMin"],
                        ["R4", "testMax"],
                        ["R4", "testSums"],
                        ["R4", "testSquares"]
                    ]
recordInfo['PTR'] = [
                        ["U4", "testNumber"],
                        ["U1", "headNumber"],
                        ["U1", "siteNumber"],
                        ["B1", "testFlag"],
                        ["B1", "parmFlag"],
                        ["R4", "testResult"],
                        ["CN", "testText"],
                        ["CN", "alarmID"],
                        ["B1", "optFlag"],
                        ["I1", "resultScale"],
                        ["I1", "llmScale"],
                        ["I1", "hlmScale"],
                        ["R4", "loLimit"],
                        ["R4", "hiLimit"],
                        ["CN", "units"],
                        ["CN", "cResFmt"],
                        ["CN", "cLlmFmt"],
                        ["CN", "cHlmFmt"],
                        ["R4", "loSpec"],
                        ["R4", "hiSpec"]
                    ]
recordInfo['MPR'] = [
                        ["U4",   "testNumber"],
                        ["U1",   "headNumber"],
                        ["U1",   "siteNumber"],
                        ["B1",   "testFlag"],
                        ["B1",   "parmFlag"],
                        ["U2",   "rtnIcnt"],
                        ["U2",   "resultCount"],
                        ["jxN1", "returnStates"],
                        ["kxR4", "returnResults"],
                        ["CN",   "testText"],
                        ["CN",   "alarmID"],
                        ["B1",   "optFlag"],
                        ["I1",   "resultScale"],
                        ["I1",   "llmScale"],
                        ["I1",   "hlmScale"],
                        ["R4",   "loLimit"],
                        ["R4",   "hiLimit"],
                        ["R4",   "startIn"],
                        ["R4",   "incrIn"],
                        ["jxU2", "returnIndexes"],
                        ["CN",   "units"],
                        ["CN",   "unitsIn"],
                        ["CN",   "cResFmt"],
                        ["CN",   "cLlmFmt"],
                        ["CN",   "cHlmFmt"],
                        ["R4",   "loSpec"],
                        ["R4",   "hiSpec"]
                    ]
recordInfo['FTR'] = [
                        ["U4",   "testNumber"],
                        ["U1",   "headNumber"],
                        ["U1",   "siteNumber"],
                        ["B1",   "testFlag"],
                        ["B1",   "optFlag"],
                        ["U4",   "cycleCount"],
                        ["U4",   "relativeVectorAddress"],
                        ["U4",   "repeatCount"],
                        ["U4",   "numFail"],
                        ["I4",   "xFailAddress"],
                        ["I4",   "yFailAddress"],
                        ["I2",   "vectorOffset"],
                        ["U2",   "returnIcnt"],
                        ["U2",   "programmedIcnt"],
                        ["jxU2", "returnIndexes"],
                        ["jxN1", "returnStates"],
                        ["kxU2", "programmedIndexes"],
                        ["kxN1", "programmedStates"],
                        ["DN",   "failPin"],
                        ["CN",   "vectorName"],
                        ["CN",   "timeSet"],
                        ["CN",   "opCode"],
                        ["CN",   "testText"],
                        ["CN",   "alarmID"],
                        ["CN",   "programmedText"],
                        ["CN",   "resultText"],
                        ["U1",   "patternGeneratorNumber"],
                        ["DN",   "spinMap"]
                    ]
recordInfo['BPS'] = [
                        ["CN", "sequencerName"]
                    ]
recordInfo['EPS'] = []
recordInfo['GDR'] = [
                        ["U2", "fieldCount"],
                        ["VN", "genericData"]
                    ]
recordInfo['DTR'] = [
                        ["CN", "textData"]
                    ]


recordInfoKeys = recordInfo.keys();
recordInfoKeys.sort()

#recordInfoTwo = {}
#recordInfoTwo['WRR']['function'] =
#'''Contains the result information relating to each wafer tested by the job plan. The WRR
#and the Wafer Information Record (WIR) bracket all the stored information pertaining to one tested wafer. This record is used only when testing at wafer probe time. A
#WIR/WRR pair will have the same HEAD_NUM and SITE_GRP values.'''

def genCode(lang):
	if lang == "cpp":
		definitionTemplate = cppDefinitionTemplate
		implementationTemplate = cppImplementationTemplate
	elif lang == "cs":
		definitionTemplate = csDefinitionTemplate
		implementationTemplate = csImplementationTemplate
	else:
		return;
	#
	#   Generate .h file entries
	#   * Class declaration
	#
	for record in recordInfoKeys:
		recordName = record + "Record"
		memberList = recordInfo[record]
		members = ""
		for i in range(len(memberList)):
			typeName = memberList[i][0]
			varName  = memberList[i][1]
			m = re.match( r"[jk]x", typeName)
			members = members + "\t\t" + typeName + " " + varName + ";\n"
		print definitionTemplate.substitute( CLASSNAME=recordName, MEMBERS=members, RECORD=record)

	#
	#   Generate .cpp file entries
	#   * Class definition
	#
	for record in recordInfoKeys:
		recordName = record + "Record"
		memberList = recordInfo[record]
		lengthStr     = ""
		getFieldStr   = ""
		initializeStr = ""
		members       = ""
		for i in range(len(memberList)):
			typeName = memberList[i][0]
			varName  = memberList[i][1]
			templated = False
			if base.has_key(typeName):
				initValue = base[typeName]['default']
				if len(memberList[i]) > 2:
					initValue = memberList[i][2]
				if initValue != "":
					initializeStr = initializeStr + "\t" + varName + " = " + initValue + ";\n"
			else:
				if typeName.find( "x") <> -1:
					vars = typeName.split( "x")
					typeName = vars[1]
					templated = True
				else:
					print "ERROR : ", typeName
					exit()
			#typeName = vectorTemplate + "<" + vars[1] + ">"
			if templated == True:
				members = members + "            " + vectorTemplate + "<" + typeName + ">" + " " + varName + ";\n"
			else:
				members = members + "            " + typeName + " " + varName + ";\n"
			numBytes = base[typeName]['size']
			numBytesStr = str(numBytes)
			if numBytes == 0:
				numBytesStr = varName + ".getLength()"
			lengthStr = lengthStr + "\t" + "len += " + numBytesStr + "; // " + typeName + " " + varName + "\n"
			if lang == "cpp":
				getFieldStr = getFieldStr + "\t" + "fields.push_back( make_pair( \"" + varName + "\",\t" + "toString(" + varName + ") ) )" + ";\n";
			elif lang == "cs":
				getFieldStr = getFieldStr + "\t" + "fields.Add( new Pair<string, string>( \"" + varName + "\",\t" + varName + ".ToString() ) )" + ";\n";
			else:
				getFieldStr = ""
		print implementationTemplate.substitute( CLASSNAME=recordName, 
				RECORD=record, INITIALIZE=initializeStr, LENGTH=lengthStr, 
				GETFIELD=getFieldStr, MEMBERS=members)

if __name__ == "__main__":
	genCode("cpp")
	genCode("cs")

